use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::io::{BufReader, BufWriter, SeekFrom};
use std::path::Path;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crc::crc32;
use serde_derive::{Deserialize, Serialize};

type ByteString = Vec<u8>; //很多地方处理Vec<u8>数据，与String具有相同的使用方式，所以此处取别名

type ByteStr = [u8];

#[derive(Debug, Serialize, Deserialize)] //自动生成序列化代码
pub struct KeyValuePair {
    pub key: ByteString,
    pub value: ByteString,
}

#[derive(Debug)]
pub struct ActionKV {
    f: File,
    pub index: HashMap<ByteString, u64>, //维护一个从键到文件位置的映射。
}

impl ActionKV {
    pub fn open(path: &Path) -> io::Result<Self> {
        let f = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .append(true)
            .open(path)?;
        let index = HashMap::new();
        Ok(ActionKV { f, index })
    }

    fn process_record<R: Read>(f: &mut R) -> io::Result<KeyValuePair> {
        //f可以是实现了Read的任何类型，比如用于读取文件的一个类型，&[u8]也是可以用在这里的类型
        //读取整数
        let saved_checksum = f.read_u32::<LittleEndian>()?;
        let key_len = f.read_u32::<LittleEndian>()?;
        let val_len = f.read_u32::<LittleEndian>()?;

        let data_len = key_len + val_len;

        let mut data = ByteString::with_capacity(data_len as usize);
        {
            f.by_ref() //使用f.by_ref(),因为toke(n)会创建一个新的read值，在一个短生命周期的代码块中使用一个引用，让我们绕过所有权问题
                .take(data_len as u64)
                .read_to_end(&mut data)?;
        }
        debug_assert_eq!(data.len(), data_len as usize); //测试在优化构建中是默认关闭的

        let checksum = crc32::checksum_ieee(&data); //校验从磁盘中读取的字节数据与预期是否一致
        if checksum != saved_checksum {
            panic!(
                "data corruption encountered ({:08x} != {:08x})",
                checksum, saved_checksum
            );
        }

        let value = data.split_off(key_len as usize); //split_off(n)把Vec<T>在n处切分成两份
        let key = data;

        Ok(KeyValuePair { key, value })
    }

    pub fn load(&mut self) -> io::Result<()> {
        //填充结构体索引
        let mut f = BufReader::new(&mut self.f);
        loop {
            let position = f.seek(SeekFrom::Current(0))?; //File::seek()返回距离文件开头位置的字节数，并将其作为该索引中的值

            let maybe_key = ActionKV::process_record(&mut f); //从文件当前位置读取一条记录

            let kv = match maybe_key {
                Ok(kv) => kv,
                Err(err) => {
                    match err.kind() {
                        io::ErrorKind::UnexpectedEof => {
                            //没有预料到会遇到文件末尾，处理这种情况
                            break;
                        }
                        _ => return Err(err),
                    }
                }
            };
            self.index.insert(kv.key, position);
        }

        Ok(())
    }

    pub fn get(&mut self,key:&ByteStr)->io::Result<Option<ByteString>>{

    }

    pub fn find(&mut self,target:&ByteStr)->io::Result<Option<(u64,ByteString)>>{

    }

    pub fn insert(&mut self,key:&ByteStr,value:&ByteStr) -> io::Result<()>{

    }

    pub fn insert_but_ignore_index(&mut self,key:&ByteStr,value:&ByteStr)->io::Result<u64>{

    }

    #[inline]
    pub fn update(){}

    #[inline]
    pub fn delete(){}
}
